/*
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package commandhandlers;

import input.IRCCommand;
import interfaces.CommandHandler;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import main.CommonMethods;
import main.Constants;
import main.Main;
import main.UserCentral;

import org.apache.log4j.Logger;
import org.jibble.pircbot.Colors;

import output.IRCOutput;
import tools.StringTools;
import botobjects.Farm;
import botobjects.Province;
import database.DBConnectionFactory;

/**
 * This class takes care of the functions related to provinces
 * 
 * 
 */
public class ProvinceHandler extends CommandHandler {
   private static ProvinceHandler INSTANCE = null;

   public static final ProvinceHandler getInstance() {
	  if (INSTANCE == null) {
		 INSTANCE = new ProvinceHandler();
	  }
	  return INSTANCE;
   }

   public static final ProvinceHandler newInstance() {
	  INSTANCE = null;
	  return getInstance();
   }

   private ProvinceHandler() {
   }

   /**
    * Removes the specified farm
    */
   private List<String> delFarm(final int no) {
	  List<String> out = new LinkedList<String>();
	  if (no < 1)
		 return out;
	  Statement stmt = null;
	  ResultSet rs = null;
	  try {
		 stmt = DBConnectionFactory.getConnectionHandler().getConnection()
			   .createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
		 String query = "SELECT * FROM farm ORDER BY updated DESC";
		 rs = stmt.executeQuery(query);

		 int i = 1;
		 while (rs.next()) {
			if (i == no) {
			   rs.deleteRow();
			   out.add("Farm deleted");
			   break;
			}
			++i;
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			stmt.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns information about what the player of the specified province needs to train to catch up with the specified build
    * 
    * @param province
    * @return
    */
   private List<String> getTrainingInfo(final String province, final String type) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM " + "province,sot WHERE province.name = ? AND province.name = sot.name");
		 ps.setString(1, province);
		 rs = ps.executeQuery();

		 if (rs.next()) {
			String race = rs.getString("race");
			String pers = rs.getString("personality");
			int land = rs.getInt("land");
			int ospecs = rs.getInt("ospecs");
			int dspecs = rs.getInt("dspecs");
			int elites = rs.getInt("elites");
			int wizards = rs.getInt("wizards");
			int thieves = rs.getInt("thieves");

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM " + "province,som WHERE province.name = ? AND province.name = som.name");
			ps.setString(1, province);
			rs = ps.executeQuery();

			if (rs.next()) {
			   ospecs += rs.getInt("ospecstraining");
			   dspecs += rs.getInt("dspecstraining");
			   elites += rs.getInt("elitestraining");
			   thieves += rs.getInt("thievestraining");
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM " + "build WHERE (racepers = ? OR racepers = ?) AND buildtype = ?");
			ps.setString(1, race);
			ps.setString(2, race + " " + pers);
			ps.setString(3, type);
			rs = ps.executeQuery();

			if (rs.next()) {
			   Double os = rs.getDouble("ospa") * land;
			   Double ds = rs.getDouble("dspa") * land;
			   Double e = rs.getDouble("epa") * land;
			   Double t = rs.getDouble("tpa") * land;
			   Double w = rs.getDouble("wpa") * land;

			   out.add(Colors.BLUE + province + ": " + Colors.OLIVE + "Ospecs" + Colors.NORMAL + " (" + rs.getDouble("ospa")
					 + ") " + Colors.BLUE + (os.intValue() - ospecs) + Colors.NORMAL + " <> " + Colors.OLIVE + "Dspecs"
					 + Colors.NORMAL + " (" + rs.getDouble("dspa") + ") " + Colors.BLUE + (ds.intValue() - dspecs)
					 + Colors.NORMAL + " <> " + Colors.OLIVE + "Elites" + Colors.NORMAL + " (" + rs.getDouble("epa") + ") "
					 + Colors.BLUE + (e.intValue() - elites) + Colors.NORMAL + " <> " + Colors.OLIVE + "Thieves" + Colors.NORMAL
					 + " (" + rs.getDouble("tpa") + ") " + Colors.BLUE + (t.intValue() - thieves) + Colors.NORMAL + " <> "
					 + Colors.OLIVE + "Wizards" + Colors.NORMAL + " (" + rs.getDouble("wpa") + ") " + Colors.BLUE
					 + (w.intValue() - wizards));
			} else {
			   out.add("No build for your race/pers");
			}
		 } else {
			out.add("No intel found");
		 }

	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   @Override
   public void handle(final IRCCommand command, final IRCOutput output) {
   }

   public void handleAddprov(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() > 4) {
		 String user = CommonMethods.getUserFromDB(command.get(1), false);
		 String msg = command.getPartialMessage(2, command.size());

		 if ("".equals(user)) {
			out.addOutput("No such user");
			return;
		 }
		 String raceregex = CommonMethods.getRacesRegex(false);
		 String persregex = CommonMethods.getPersonalitiesRegex();

		 Pattern pattern = Pattern.compile(raceregex + " " + persregex + " (.*)");
		 Matcher matcher = pattern.matcher(msg);

		 if (!matcher.matches())
			return;

		 String race = matcher.group(1);
		 String pers = matcher.group(2);
		 String prov = matcher.group(3);

		 race = StringTools.capitalizeFirstLetters(race);
		 pers = StringTools.capitalizeFirstLetters(pers);

		 if (new Province(user, prov, "(" + Main.getBotSettings().getKdLoc() + ")", race, pers, "", 0, 0).saveToDB()) {
			out.addOutput("Province added successfully");
			Province.updateThieves(prov, 0);
		 }
	  }
   }

   public void handleFarm(final IRCCommand command, final IRCOutput out) {
	  if (command.size() < 3)
		 return;
	  else {
		 String msg = command.getFullMessage();
		 if (!msg.matches(".*\\([0-9]{1,2}(:)[0-9]{1,2}\\).*"))
			return;
		 String prov = msg.substring(0, msg.indexOf('(')).trim();
		 String loc = msg.substring(msg.indexOf('('), msg.indexOf(')') + 1).trim();
		 msg = msg.substring(msg.indexOf(')') + 1);
		 if (new Farm(prov, loc, msg, Calendar.getInstance().getTimeInMillis()).saveToDB()) {
			out.addOutput("Farm added");
		 }
	  }
   }

   public void handleFarms(final IRCCommand command, final IRCOutput out) {
	  int i = 1;
	  for (Farm farm : Farm.getFarms()) {
		 out.addOutput(farm.getIRCOutput(0, String.valueOf(i)));
		 ++i;
	  }
   }

   public void handleProv(final IRCCommand command, final IRCOutput out) {
	  String searchFor = "";
	  if (command.size() == 1) {
		 searchFor = UserCentral.getInstance().getOnlineUser(command.getSender());
	  }
	  if (command.size() > 1) {
		 searchFor = command.getFullMessage();
		 String temp = CommonMethods.getUserFromDBFuzzyMatching(searchFor);
		 if (!"".equals(temp)) {
			searchFor = temp;
		 }
	  }
	  Province prov = Province.getInternalProvince(searchFor);
	  if (prov != null) {
		 out.addOutput(prov.getIRCOutput(Constants.PROVINCE_GET_OWNER));
	  }
   }

   public void handleProvlist(final IRCCommand command, final IRCOutput out) {
	  for (Province province : Province.getInternalProvinces()) {
		 out.addOutput(province.getIRCOutput(Constants.PROVINCE_GET_OWNER));
	  }
   }

   public void handleRemovefarm(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 2) {
		 if (command.isInt(1)) {
			out.addOutput(delFarm(Integer.parseInt(command.get(1))));
		 }
	  }
   }

   public void handleRemoveprov(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() > 1) {
		 String province = command.getFullMessage();
		 if (!"".equals(CommonMethods.provinceExists(province)))
			if (Province.deleteFromDB(province)) {
			   out.addOutput("Province deleted successfully");
			}
	  }
   }

   public void handleTrain(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1) {
		 String prov = CommonMethods.getProv(UserCentral.getInstance().getOnlineUser(command.getSender()));
		 if (!"".equals(prov)) {
			out.addOutput(getTrainingInfo(prov, "default"));
		 }
	  } else if (command.size() == 2) {
		 String prov = CommonMethods.getProv(CommonMethods.getUserFromDB(command.get(1), false));
		 if (!"".equals(prov)) {
			out.addOutput(getTrainingInfo(prov, "default"));
		 } else {
			String prov2 = CommonMethods.getProv(UserCentral.getInstance().getOnlineUser(command.getSender()));
			if (!"".equals(prov2)) {
			   out.addOutput(getTrainingInfo(prov2, command.get(1)));
			}
		 }
	  } else {
		 String prov = CommonMethods.getProv(CommonMethods.getUserFromDB(command.get(1), false));
		 if (!"".equals(prov)) {
			out.addOutput(getTrainingInfo(prov, command.get(2)));
		 }
	  }
   }

}
